/**
 *  Copyright 2002 Quaseem
 *  Copyright 2004 Migisan
 *  Copyright 2008 Oest
 *
 *  This file is part of the aochat package.
 *
 *  The aochat package is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  The aochat package is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with the aochat package; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

package sk.sigp.aobot.client.core.message;

import java.util.Random;
import java.math.BigInteger;

import sk.sigp.aobot.client.core.message.general.Message;
import sk.sigp.aobot.client.types.Int;
import sk.sigp.aobot.client.types.Text;

public class LoginMessage extends Message {
	private static final long serialVersionUID = 1234L;

	private static final String seed1 = "eca2e8c85d863dcdc26a429a71a9815ad052f6139669dd659f98ae159d313d13c6bf2838e10a69b6478b64a24bd054ba8248e8fa778703b418408249440b2c1edd28853e240d8a7e49540b76d120d3b1ad2878b1b99490eb4a2a5e84caa8a91cecbdb1aa7c816e8be343246f80c637abc653b893fd91686cf8d32d6cfe5f2a6f";
	private static final String seed2 = "9c32cc23d559ca90fc31be72df817d0e124769e809f936bc14360ff4bed758f260a0d596584eacbbc2b88bdd410416163e11dbf62173393fbc0c6fefb2d855f1a03dec8e9f105bbad91b3437d8eb73fe2f44159597aa4053cf788d2f9d7012fb8d7c4ce3876f7d6cd5d0c31754f4cd96166708641958de54a6def5657b9f2e92";
	private static final String seed3 = "5";

	public LoginMessage(String username, String password, String serverSeed) {
		super(M_C_LOGIN_RESPONSE_GETCHARACTERLIST);
		setElementAt(0, new Int(0));
		setElementAt(1, new Text(username));
		setElementAt(2, makeResponse(makeRandomSeed(), username, serverSeed,
				password));
	}

	private String encrypt(String seed, String content) {
		byte byte0 = 4;
		if (seed.length() < 32) {
			System.out.println("Too short input key.");
			return null;
		}
		int ai[] = new int[seed.length() / 2];
		strint(seed, ai);
		String s2 = intstr(0);
		String s3 = "";
		String s4 = "";
		for (int i = 0; i < 8; i++)
			s3 = s3 + String.valueOf((char) (int) (Math.random() * 255D));

		int j = s3.length() + s2.length() + content.length();
		int k = 8 - j % 8;
		if (k != 8) {
			j += k;
			for (int l = 0; l < k; l++)
				s4 = s4 + ' ';

		}
		s2 = intstr(content.length());
		String s5 = s3 + s2 + content + s4;
		int ai1[] = new int[s5.length() / byte0];
		strToInt(s5, ai1);
		int ai2[] = { 0, 0 };
		int ai3[] = new int[2];
		String s6 = "";
		ai3[0] = ai1[0];
		ai3[1] = ai1[1];
		for (int i1 = 0; i1 < ai1.length; i1 += 2) {
			if (i1 != 0) {
				ai3[0] = ai1[i1];
				ai3[1] = ai1[i1 + 1];
				ai3[0] ^= ai2[0];
				ai3[1] ^= ai2[1];
			}
			transf(ai3, ai);
			ai2[0] = ai3[0];
			ai2[1] = ai3[1];
			s6 = s6 + intToHexStr(ai3);
		}
		return s6;
	}

	private String intstr(int i) {
		char ac[] = new char[4];
		ac[0] = (char) (i >>> 24 & 0xff);
		ac[1] = (char) (i >>> 16 & 0xff);
		ac[2] = (char) (i >>> 8 & 0xff);
		ac[3] = (char) (i >>> 0 & 0xff);
		return new String(ac);
	}

	private void strint(String s, int ai[]) {
		int i = 0;
		int j = 0;
		for (int k = 0; k < s.length(); k += 2) {
			String s1 = s.substring(k, k + 2);
			ai[j] |= Integer.parseInt(s1, 16) << i;
			if ((i += 8) == 32) {
				i = 0;
				if (++j == ai.length)
					return;
			}
		}
	}

	private void strToInt(String s, int ai[]) {
		int i = 0;
		int j = 0;
		for (int k = 0; k < s.length(); k++) {
			ai[j] |= (s.charAt(k) & 0xff) << i;
			if ((i += 8) == 32) {
				i = 0;
				if (++j == ai.length)
					return;
			}
		}

	}

	private void transf(int ai[], int ai1[]) {
		int i = ai[0];
		int j = ai[1];
		int k = 0;
		int l = 0x9e3779b9;
		for (int i1 = 32; i1-- > 0;) {
			k += l;
			i += (j << 4 & 0xfffffff0) + ai1[0] ^ j + k ^ (j >> 5 & 0x7ffffff)
					+ ai1[1];
			j += (i << 4 & 0xfffffff0) + ai1[2] ^ i + k ^ (i >> 5 & 0x7ffffff)
					+ ai1[3];
		}

		ai[0] = i;
		ai[1] = j;
	}

	private static String intToHexStr(int ai[]) {
		String s = "";
		for (int i = 0; i < ai.length; i++) {
			for (int j = 0; j < 32; j += 8) {
				int k = ai[i] >> j & 0xff;
				if (k < 16)
					s = s + "0" + Integer.toHexString(k);
				else
					s = s + Integer.toHexString(k);
			}
		}

		return s;
	}

	private String fill(int i, String s, String s1) {
		if (s.length() < i) {
			int j = i - s.length();
			for (int k = 0; k < j; k++)
				s = s1 + s;

			return s;
		} else {
			return s;
		}
	}

	private String makeRandomSeed() {
		Random rand = new Random(System.currentTimeMillis());

		int j = 128 / 8;
		StringBuffer stringbuffer = new StringBuffer(j * 2);
		for (int k = 0; k < j; k++) {
			int l = rand.nextInt() & 255; // Low-Byte
			stringbuffer.append(Integer.toString(l, 16));
		}
		return stringbuffer.toString();
	}

	private Text makeResponse(String randomSeed, String username,
			String serverSeed, String password) {
		BigInteger biginteger = new BigInteger(seed1, 16);
		BigInteger biginteger1 = new BigInteger(seed2, 16);
		BigInteger biginteger2 = new BigInteger(seed3, 16);
		BigInteger biginteger3 = new BigInteger(randomSeed, 16);
		BigInteger biginteger4 = biginteger2.modPow(biginteger3, biginteger);
		BigInteger biginteger5 = biginteger1.modPow(biginteger3, biginteger);
		String s4 = username + "|" + serverSeed + "|" + password;
		String s5 = biginteger5.toString(16);
		String s6 = fill(32, s5, "0").substring(0, 32);
		String s7 = encrypt(s6, s4);
		String s8 = biginteger4.toString(16) + "-" + s7;
		return new Text(s8);
	}
}
